#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UTable.Input.MultiTouch;
using System.Collections.ObjectModel;
using System.Windows;
using UTable.Objects.Controls;

namespace UTable.Objects.Handlers
{
    public abstract class CertainFingerGestureHandler : MultiTouchEventHandlerClass
    {
        #region Private Fields

        private IInputNode _node = null;

        private bool _captureFingers = true;

        private bool _handleAllEvents = true;

        private bool _stopRouteDown = true;

        #endregion

        #region Properties

        protected Collection<FingerEventArgs> CurrentFingers = new Collection<FingerEventArgs>();

        public IInputNode Node 
        { 
            get { return _node; } 
        }

        /// <summary>
        /// Indicate whether the fingers handled by this class is captured
        /// </summary>
        public bool CaptureFingers
        {
            get { return _captureFingers; }
            set { _captureFingers = value; }
        }

        public Boolean HandleAllEvents
        {
            get { return _handleAllEvents; }
            set { _handleAllEvents = value; }
        }

        public Boolean StopRouteDown
        {
            get { return _stopRouteDown; }
            set { _stopRouteDown = value; }
        }

        #endregion


        /// <summary>
        /// The number of fingers that are handled by this handler
        /// </summary>
        public abstract int FingerNumber { get; }

        public abstract void OnCertainFingersDown(Collection<FingerEventArgs> fingers);

        public abstract void OnCertainFingersMove(Collection<FingerEventArgs> fingers);

        public abstract void OnCertainFingersUp(Collection<FingerEventArgs> fingers);

        public abstract void OnCertainFingersCancelled(Collection<FingerEventArgs> fingers);


        public CertainFingerGestureHandler(IControl node)
        {
            _node = node;
        }

        public override void OnMultiTouch(MultiTouchEventArgs args)
        {
            foreach (FingerEventArgs fargs in args.FingerEvents)
            {
                switch (fargs.EventType)
                {
                    case FingerEventType.FINGER_DOWN_EVENT:
                        OnContactDown(fargs);
                        break;
                    case FingerEventType.FINGER_MOVE_EVENT:
                        OnContactMove(fargs);
                        break;
                    case FingerEventType.FINGER_UP_EVENT:
                        OnContactUp(fargs);
                        break;
                }
            }
            if (HandleAllEvents)
                args.Handled = true;
            if (StopRouteDown)
                args.RouteDown = false;
        }

        #region Private Methods

        protected virtual void OnContactDown(FingerEventArgs args)
        {
            if (CurrentFingers.Count > FingerNumber)
            {
                // do nothing
            }
            else if (CurrentFingers.Count == FingerNumber)
            {
                // OnCertainFingersCancelled(CurrentFingers);
            }
            else
            {
                if (CaptureFingers)
                    _node.CaptureFinger(args.FingerID);
                CurrentFingers.Add(args);
                args.Handled = true;
                if (CurrentFingers.Count == FingerNumber)
                    OnCertainFingersDown(CurrentFingers);
            }
        }

        protected virtual void OnContactMove(FingerEventArgs args)
        {
            if (CurrentFingers.Count == FingerNumber && HoldFinger(args.FingerID))
            {
                args.Handled = true;
                UpdateFingerStatus(args);
                OnCertainFingersMove(CurrentFingers);
            }
        }

        protected virtual void OnContactUp(FingerEventArgs args)
        {
            if (HoldFinger(args.FingerID))
            {
                if (CurrentFingers.Count == FingerNumber)
                {
                    UpdateFingerStatus(args);
                    if (CaptureFingers)
                        _node.UncaptureFinger(args.FingerID);
                    args.Handled = true;
                    OnCertainFingersUp(CurrentFingers);
                }
                RemoveFinger(args.FingerID);
            }
        }

        protected void RemoveFinger(int fingerId)
        {
            for (int i = 0; i < CurrentFingers.Count; i++)
            {
                if (CurrentFingers[i].FingerID == fingerId)
                {
                    CurrentFingers.RemoveAt(i);
                    return;
                }
            }
        }

        protected void UpdateFingerStatus(FingerEventArgs finger)
        {
            foreach (FingerEventArgs f in CurrentFingers)
                if (f.FingerID == finger.FingerID)
                {
                    f.EventType = finger.EventType;
                    f.GlobalPosition = finger.GlobalPosition;
                    f.Position = finger.Position;
                    f.Timestamp = finger.Timestamp;
                    return;
                }
        }

        protected bool HoldFinger(int fingerId)
        {
            foreach (FingerEventArgs finger in CurrentFingers)
                if (finger.FingerID == fingerId)
                    return true;
            return false;
        }
        #endregion
    }
}
